import { Inject, Injectable } from '@nestjs/common';
import { UserService } from '../user/user.service';
import { isEmpty } from 'lodash';
import { ErrorEnum } from '../../constants/error-code.constant';
import { BusinessException } from '~/common/exceptions/biz.exception';
import { md5 } from '~/utils/crypto.util';
import { RoleService } from '../system/role/role.service';
import { ISecurityConfig, SecurityConfig } from '~/config/security.config';
import Redis from 'ioredis';
import { InjectRedis } from '~/common/decorators/inject-redis.decorator';
import { genAuthPermKey, genAuthTokenKey } from '~/helper/genRedisKey';
import { MenuService } from '../system/menu/menu.service';
import { LoginDto } from './dto/auth.dto';
import { JwtService } from '@nestjs/jwt';
import { TokenService } from './services/token.service';
// import { AccessTokenEntity } from './entities/access-token.entity';
// import { UserEntity } from '../user/user.entity';
// import dayjs from 'dayjs';
@Injectable()
export class AuthService {
  constructor(
    @InjectRedis() private readonly redis: Redis,
    private jwtService: JwtService,
    @Inject(SecurityConfig.KEY) private securityConfig: ISecurityConfig,
    private userService: UserService,
    private roleService: RoleService,
    private menuService: MenuService,
    private tokenService: TokenService
  ) {}

  async validateUser(username: string, password: string): Promise<any> {
    const user = await this.userService.findUserByUserName(username);
    if (isEmpty(user)) {
      throw new BusinessException(ErrorEnum.USER_NOT_FOUND);
    }
    const comparePassword = md5(`${password}${user.psalt}`);
    if (user.password !== comparePassword) {
      throw new BusinessException(ErrorEnum.INVALID_USERNAME_PASSWORD);
    }

    if (user) {
      const { password, ...result } = user;
      console.log(password, 'password');
      return result;
    }

    return null;
  }

  async login(userDto: LoginDto) {
    const { username, password } = userDto;
    const user = await this.userService.findUserByUserName(username);
    // 判断用户是否为空
    if (isEmpty(user)) {
      throw new BusinessException(ErrorEnum.INVALID_USERNAME_PASSWORD);
    }
    // // 判断密码是否正确
    const comparePassword = md5(`${password}${user.psalt}`);
    if (user.password !== comparePassword) {
      throw new BusinessException(ErrorEnum.INVALID_USERNAME_PASSWORD);
    }
    const roleIds = await this.roleService.getRoleIdsByUser(user.id);
    const roles = await this.roleService.getRoleValues(roleIds);
    // 包含access_token和refresh_token
    const token = await this.tokenService.generateAccessToken(user.id, roles);
    await this.redis.set(
      genAuthTokenKey(user.id),
      token.accessToken,
      'EX',
      this.securityConfig.jwtExprire
    );
    const permissions = await this.menuService.getPermissions(user.id);

    return {
      accessToken: token.accessToken,
      refreshToken: token.refreshToken,
      expires: token.expires,
      permissions,
      roles,
      username,
      nickname: user.nickname,
      avatar: user.avatar
    };
  }
  async setPermissionsCache(uid: number, permissions: string[]): Promise<void> {
    await this.redis.set(genAuthPermKey(uid), JSON.stringify(permissions));
  }
  async getPermissions(uid: number): Promise<string[]> {
    return this.menuService.getPermissions(uid);
  }
}
